package net.toby200.canalstoppages.notify;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.googlecode.objectify.ObjectifyService;

import net.toby200.canalstoppages.Config;
import net.toby200.canalstoppages.model.AndroidRegistrationId;
import net.toby200.canalstoppages.model.Notice;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import static com.googlecode.objectify.ObjectifyService.ofy;

/**
 * Created by toby on 16/11/2014.
 */
public class Notifier {
    private static final Logger LOG = Logger.getLogger(Notifier.class.getName());

    private static final ObjectMapper m = new ObjectMapper();

    static {
        ObjectifyService.register(AndroidRegistrationId.class);
    }

    public static void sendNotification(Collection<Notice> updatedNotices) {
        if (updatedNotices.size() < 1) {
            LOG.log(Level.INFO, "No updated notices");
            return;
        }
        Sender sender = new Sender(Config.API_KEY);

        Set<AndroidRegistrationId> regIds = new HashSet<AndroidRegistrationId>(ofy().load().type(AndroidRegistrationId.class).list());

        for (Notice notice : updatedNotices) {
            sendNotification(sender, notice, regIds);
        }
    }

    private static void sendNotification(Sender sender, Notice notice, Set<AndroidRegistrationId> regIds) {
        Message msg;
        try {
            String json = m.writeValueAsString(notice);
            msg = new Message.Builder().addData("notice", json).build();
        } catch (JsonProcessingException e) {
            LOG.log(Level.SEVERE, "Unable to serialize notice", e);
            return;
        }

        for(AndroidRegistrationId record : regIds) {
            try {
                Result result = sender.send(msg, record.getId(), 5);
                if (result.getMessageId() != null) {
                    LOG.info("Message sent to " + record.getId());
                    String canonicalRegId = result.getCanonicalRegistrationId();
                    if (canonicalRegId != null) {
                        // if the regId changed, we have to update the datastore
                        LOG.info("Registration Id changed for " + record.getId() + " updating to " + canonicalRegId);
                        record.setId(canonicalRegId);
                        ofy().save().entity(record).now();

                    }
                } else {
                    String error = result.getErrorCodeName();
                    if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
                        LOG.warning("Registration Id " + record.getId() + " no longer registered with GCM, removing from datastore");
                        // if the device is no longer registered with Gcm, remove it from the datastore
                        ofy().delete().entity(record).now();
                        regIds.remove(record);
                    } else {
                        LOG.warning("Error when sending message : " + error);
                    }
                }
            } catch (Exception e) {
                LOG.log(Level.SEVERE, "Unable to send notification", e);
            }
        }
    }

}
